﻿using StackExchange.Redis;
using System;
using System.Threading.Tasks;
using X23.Util.SerializationUtil;
using static X23.Util.CacheUtil.CacheConst;

namespace X23.Util.CacheUtil
{
    public class RedisCacheService : ICacheService
    {
        private readonly IDatabase _database;
        /// <summary>
        /// 过期类型key  辅助值
        /// </summary>
        private readonly string KeyByExpiration = "_KeyByExpiration";

        //private readonly ConnectionMultiplexer _redisCache;

        public RedisCacheService(ConnectionMultiplexer redisCache)
        {
            //_redisCache = redisCache;
            _database = redisCache.GetDatabase();
        }
        public async Task<string> GetAsync(string key)
        {
            var result = await _database.StringGetAsync(key);

            //如果滑动过期
            if (await _database.KeyExistsAsync(key + KeyByExpiration))
            {
                var valueKeyByExpiration = int.Parse(await _database.StringGetAsync(key + KeyByExpiration));
                await SetSlidingExpirationKey(key, valueKeyByExpiration);
            }

            return result;
        }
        public async Task<string> GetOrCreateAsync(string key, Func<Task<string>> func, int minutes = 60, ExpirationType expirationType = ExpirationType.AbsoluteExpiration)
        {
            RedisValue result;
            if (await _database.KeyExistsAsync(key))
            {
                result = await GetAsync(key);
            }
            else
            {
                result = await func();
                if (!await SetAsync(key, result, minutes, expirationType))
                {
                    throw new Exception("添加redis缓存失败！");
                }
            }
            return result;
        }
        public async Task<int> IncrementAsync(string key, int inc = 0)
        {
            var result = await _database.StringIncrementAsync(key, inc);
            try
            {
                return Convert.ToInt32(result);
            }
            catch (Exception e)
            {
                throw new Exception($"Redis自增错误！key={key}，inc={inc}，result={result}。e.Message={e.Message}");
            }
        }

        public async Task<bool> RemoveAsync(string key)
        {
            if (!await _database.KeyExistsAsync(key))
            {
                return true;
            }
            RedisKey[] delKeys = new RedisKey[2] { key, key + KeyByExpiration };
            return (await _database.KeyDeleteAsync(delKeys))>0;
        }

        public async Task<bool> SetAsync(string key,string val, int minutes = 60, ExpirationType expirationType = ExpirationType.AbsoluteExpiration)
        {
            TimeSpan timeSpan = TimeSpan.FromMinutes(60);


            var result = await _database.StringSetAsync(key, val, timeSpan);

            if (expirationType == ExpirationType.SlidingExpiration)
            {
                await SetSlidingExpirationKey(key, minutes);
            }

            return result;
        }

        /// <summary>
        /// 设置滑动过期key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="minutes"></param>
        /// <returns></returns>
        private async Task<bool> SetSlidingExpirationKey(string key, int minutes)
        {
            await _database.KeyExpireAsync(key, TimeSpan.FromMinutes(minutes));
            return await _database.StringSetAsync(key + KeyByExpiration, minutes, TimeSpan.FromMinutes(minutes + 5));

        }
    }
}
